package com.dal.guava.config;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import io.lettuce.core.ClientOptions;
import io.lettuce.core.SocketOptions;
import io.lettuce.core.TimeoutOptions;

import static io.lettuce.core.resource.DnsResolver.jvmDefault;

@Configuration
public class RedisConfig {

    @Value("${spring.redis.host:localhost}")
    private String host;

    @Value("${spring.redis.port:6379}")
    private int port;

    @Value("${spring.redis.password:}")
    private String password;

    @Value("${spring.redis.timeout:3000}")
    private long timeout;

    @Value("${spring.redis.database:0}")
    private int database;

    // 连接池配置
    @Value("${spring.redis.lettuce.pool.max-active:8}")
    private int maxActive;

    @Value("${spring.redis.lettuce.pool.max-wait:-1}")
    private long maxWait;

    @Value("${spring.redis.lettuce.pool.max-idle:8}")
    private int maxIdle;

    @Value("${spring.redis.lettuce.pool.min-idle:0}")
    private int minIdle;

    // 集群配置
    @Value("${spring.redis.cluster.nodes:}")
    private String clusterNodes;

    @Value("${spring.redis.cluster.max-redirects:3}")
    private int maxRedirects;

    // 哨兵配置
    @Value("${spring.redis.sentinel.master:}")
    private String sentinelMaster;

    @Value("${spring.redis.sentinel.nodes:}")
    private String sentinelNodes;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        // 创建连接池配置
        LettuceClientConfiguration clientConfig = buildLettuceClientConfiguration();

        // 根据配置决定使用单机、集群还是哨兵模式
        if (!clusterNodes.isEmpty()) {
            return createClusterConnectionFactory(clientConfig);
        } else if (!sentinelMaster.isEmpty()) {
            return createSentinelConnectionFactory(clientConfig);
        } else {
            return createSingleConnectionFactory(clientConfig);
        }
    }

    private LettuceClientConfiguration buildLettuceClientConfiguration() {
        // 配置连接选项
        ClientOptions clientOptions = ClientOptions.builder()
                .socketOptions(SocketOptions.builder()
                        .connectTimeout(Duration.ofMillis(timeout))
                        .keepAlive(true)
                        .build())
                .timeoutOptions(TimeoutOptions.enabled(Duration.ofMillis(timeout)))
                .autoReconnect(true)
                .disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)
                .build();

        // 配置连接池
        return LettucePoolingClientConfiguration.builder()
                .clientOptions(clientOptions)
                .commandTimeout(Duration.ofMillis(timeout))
                .shutdownTimeout(Duration.ofMillis(100))
                .poolConfig(buildPoolConfig())
                .build();
    }

    private io.lettuce.core.resource.ClientResources buildClientResources() {
        return io.lettuce.core.resource.ClientResources.builder()
                .dnsResolver(jvmDefault())
                .build();
    }

    private GenericObjectPoolConfig<?> buildPoolConfig() {
        // 修复：添加了new关键字
        GenericObjectPoolConfig<?> poolConfig = new GenericObjectPoolConfig<>();
        poolConfig.setMaxTotal(maxActive);
        poolConfig.setMaxIdle(maxIdle);
        poolConfig.setMinIdle(minIdle);
        poolConfig.setMaxWaitMillis(maxWait);
        poolConfig.setTimeBetweenEvictionRunsMillis(60000);
        poolConfig.setMinEvictableIdleTimeMillis(300000);
        poolConfig.setTestOnBorrow(true);
        poolConfig.setTestOnReturn(false);
        poolConfig.setTestWhileIdle(true);
        return poolConfig;
    }

    private RedisConnectionFactory createSingleConnectionFactory(LettuceClientConfiguration clientConfig) {
        org.springframework.data.redis.connection.RedisStandaloneConfiguration config =
                new org.springframework.data.redis.connection.RedisStandaloneConfiguration(host, port);
        if (!password.isEmpty()) {
            config.setPassword(password);
        }
        config.setDatabase(database);
        return new LettuceConnectionFactory(config, clientConfig);
    }

    private RedisConnectionFactory createClusterConnectionFactory(LettuceClientConfiguration clientConfig) {
        List<String> nodes = Arrays.asList(clusterNodes.split(","));
        List<RedisNode> redisNodes = nodes.stream()
                .map(node -> {
                    String[] parts = node.split(":");
                    return new RedisNode(parts[0].trim(), Integer.parseInt(parts[1].trim()));
                })
                .collect(Collectors.toList());

        RedisClusterConfiguration config = new RedisClusterConfiguration();
        config.setClusterNodes(redisNodes);
        config.setMaxRedirects(maxRedirects);
        if (!password.isEmpty()) {
            config.setPassword(password);
        }
        return new LettuceConnectionFactory(config, clientConfig);
    }

    private RedisConnectionFactory createSentinelConnectionFactory(LettuceClientConfiguration clientConfig) {
        List<String> nodes = Arrays.asList(sentinelNodes.split(","));
        List<RedisNode> redisNodes = nodes.stream()
                .map(node -> {
                    String[] parts = node.split(":");
                    return new RedisNode(parts[0].trim(), Integer.parseInt(parts[1].trim()));
                })
                .collect(Collectors.toList());

        RedisSentinelConfiguration config = new RedisSentinelConfiguration();
        config.setMaster(sentinelMaster);
        config.setSentinels(redisNodes);
        if (!password.isEmpty()) {
            config.setPassword(password);
        }
        config.setDatabase(database);
        return new LettuceConnectionFactory(config, clientConfig);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        // 设置key序列化方式
        template.setKeySerializer(new StringRedisSerializer());

        // 设置value序列化方式
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        // 设置hash key序列化方式
        template.setHashKeySerializer(new StringRedisSerializer());

        // 设置hash value序列化方式
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());

        template.afterPropertiesSet();
        return template;
    }
}